#include "Log.hpp"
#include <iostream>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>

using namespace LogModule;
using func_t = std::function<std::string(const std::string&)>;

class UdpServer
{
public:
    UdpServer(uint16_t port,func_t func)
    :_sockfd(-1)
    ,_port(port)
    ,_isrunning(false)
    ,_func(func)
    {

    }

    void Init()
    {
        //1.创建套接字
        _sockfd = socket(AF_INET,SOCK_DGRAM,0);//Udp
        if(_sockfd < 0)
        {
            LOG(LogLevel::FATAL)<<"socket create error";
            exit(1);
        }
        LOG(LogLevel::INFO)<<"socket create success:"<<_sockfd;                   

        //2.绑定socket信息--端口号，ip不用绑
        struct sockaddr_in local;
        bzero(&local,sizeof(local));//string.h库中填充0的函数
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);//绑定端口号
        local.sin_addr.s_addr = INADDR_ANY;//绑定任意ip

        int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n < 0)
        {
            LOG(LogLevel::FATAL)<<"bind error";
            exit(2);
        }
        LOG(LogLevel::INFO)<<"bind success";
    }

    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            char buffer[1024];
            struct sockaddr_in peer;//接收客户端信息，然后再发送回去
            socklen_t len = sizeof(peer);
            //1.接收消息
            ssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&peer,&len);
            if(s > 0)
            {
                //这样就可以得到客户端的ip和端口了，这是展示如何获得
                int peer_port = ntohs(peer.sin_port);
                std::string peer_ip = inet_ntoa(peer.sin_addr);//4字节网络风格ip转换为点分十进制的字符串

                buffer[s] = 0;
                std::string result = _func(buffer);//调用func处理信息后再发送回去
                
                sendto(_sockfd,result.c_str(),sizeof(result),0,(struct sockaddr*)&peer,len);
            }
        }
    }

    ~UdpServer(){}
private:
    int _sockfd;
    uint16_t _port;
    //std::string _ip;服务端不绑定指定ip
    bool _isrunning;

    func_t _func;
};